home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-04
/
dm3_src.zip
/
DMCOMMIO.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-04-26
|
58KB
|
1,638 lines
;* ************************************************************************* *;
;* *;
;* M Y C R O F T D M L I B R A R Y 3 . 0 0 *;
;* Low Level Comm Port I/O Functions *;
;* *;
;* ************************************************************************* *;
;==========================
; User Defined Definitions
;==========================
; Note: The buffer sizes must be an even power of 2 (ie. 32, 64, 1024, etc).
; An input buffer of 16 to 64 and an output buffer of 64 to 512
; should be fine for normal door use. Suggest 2K for both input and
; and output buffers for doors doing large data transfers such as
; file uploads and downloads.
;
; If the DCDW flag is set then the _comm_regs function will need to
; be called to monitor DCD. All other functions will then ignore DCD
; and will never return a status indicating it has been lost.
;
; In general, for door applications, DCDW should be set to 0. STAW
; may also be set to 0 as there is little you can do in a door in the
; event of line errors.
;
DCDW equ 0 ; 1 for ignoring loss of DCD
STAW equ 0 ; 1 for monitoring STAT register
IBUFFSIZE equ 64 ; Size of input buffer
IBUFFMASK equ IBUFFSIZE - 1 ; Circular mask for input buffer
IBUFFFULL equ IBUFFSIZE - 16 ; Limit to to take down RTS
OBUFFSIZE equ 1024 ; Size of output buffer
OBUFFMASK equ OBUFFSIZE - 1 ; Circular mask for input buffer
OBUFFFULL equ OBUFFSIZE - 16 ; Limit to wait for empty spot
;==========================
; BIOS/Fossil Definitions
;==========================
BIOS equ 14H ; BIOS Comm interrupt
BCBAUD equ 00H ; Setup comm port function
BCOUT equ 01H ; Output to comm port function
BCIN equ 02H ; Input from comm port function
BCSTAT equ 03H ; Return I/O status registers
BCINIT equ 04H ; Initialize Fossil
BCWAIT equ 08H ; Wait for output complete
BCFOUT equ 09H ; Flush output buffer
BCFIN equ 0AH ; Flush input buffer
BCTIME equ 80H ; Timeout flag
;==========================
; Comm Port Definitions
;==========================
DATA equ 00H ; data port offset
EINT equ 01H ; interrupt enable offset
EIMS equ 08H ; enable modem status int
IF STAW ;*********************************************************************
EILS equ 04H ; enable line status int
ELSE
EILS equ 00H ; do not enable line status int
ENDIF ;*********************************************************************
EITX equ 02H ; enable tx ready int
EIRX equ 01H ; enable RX avail int
IINT equ 02H ; interrupt identification
IIMK equ 06H ; interrupt id mask
IIPD equ 01H ; interrupt pending flag
LCRR equ 03H ; line control register
MCRR equ 04H ; modem control register
MCLP equ 10H ; loop back test
MCO2 equ 08H ; out2 control
MCO1 equ 04H ; out1 control
MCRT equ 02H ; RTS control
MCDT equ 01H ; DTR control
STAT equ 05H ; line status register
STTX equ 40H ; TX empty
STTH equ 20H ; TH empty
STBK equ 10H ; BREAK detected
STFE equ 08H ; framing error
STPE equ 04H ; parity error
STOE equ 02H ; overrun error
STRX equ 01H ; RX available
MODM equ 06H ; modem status register
MODC equ 80H ; DCD status
MORI equ 40H ; ring indicator
MODS equ 20H ; DSR status
MOCT equ 10H ; CTS status
;==========================
; Interrupt Controller
; Definitions
;==========================
IRQ0 equ 01H ; interrupt mask for IRQ0
IRQ1 equ 02H ; interrupt mask for IRQ1
IRQ2 equ 04H ; interrupt mask for IRQ2
IRQ3 equ 08H ; interrupt mask for IRQ3
IRQ4 equ 10H ; interrupt mask for IRQ4
IRQ5 equ 20H ; interrupt mask for IRQ5
IRQ6 equ 40H ; interrupt mask for IRQ6
IRQ7 equ 80H ; interrupt mask for IRQ7
IRQ0V equ 8 ; interrupt vector for IRQ0
IRQ1V equ 9 ; interrupt vector for IRQ1
IRQ2V equ 10 ; interrupt vector for IRQ2
IRQ3V equ 11 ; interrupt vector for IRQ3
IRQ4V equ 12 ; interrupt vector for IRQ4
IRQ5V equ 13 ; interrupt vector for IRQ5
IRQ6V equ 14 ; interrupt vector for IRQ6
IRQ7V equ 15 ; interrupt vector for IRQ7
EOIP equ 20H ; EOI port
EOIP2 equ 0A0H ; EOI port
IEOI equ 00H ; Interrupt EOI port
IMSK equ 01H ; Interrupt mask port
EOID equ 20H ; EOI data
;==========================
; DOS Interface
; Definitions
;==========================
DOS equ 21H ; DOS access vector
DOS_SET_VECTOR equ 25H ; Set interrupt vector
DOS_GET_VECTOR equ 35H ; Get interrupt vector
;==========================
; Character Definitions
;==========================
XON equ 11H ; XON character
XOFF equ 13H ; XOFF character
;==========================
; Comm Port Monitor
; For DM Library
;==========================
DMIOSEG SEGMENT 'CODE'
ASSUME cs:DMIOSEG
;==========================
; Linkage References
;==========================
public _dmcomm_init
public _dmcomm_release
public _dmcomm_status
public _dmcomm_regs
public _dmcomm_input
public _dmcomm_output
public _dmcomm_wait
public _dmcomm_iflush
public _dmcomm_oflush
;==========================
; Local Storage
;==========================
commid dw 0 ; logical comm port number to use
cport dw 0 ; comm port physical address
iport dw 20H ; 8259A port to use
cirqm db 0 ; IRQ mask to use
cirqv db 0 ; IRQ vector to use
usint dw 0 ; use interrupts flag
handsh dw 0 ; handshake to use
passth dw 0 ; passthrough the interrupt
clstat db 0 ; last line status
cmstat db 0 ; last modem status
isave db 0 ; 8259A inetrrupt mask save
sisave db 0 ; serial interrupt mask save
smsave db 0 ; serial modem control mask save
oldint dw offset _dmcomm_isr ; old interrupt vector
dw seg _dmcomm_isr
ibuffer db IBUFFSIZE dup (0) ; input buffer
iputptr dw 0 ; input put pointer
igetptr dw 0 ; input get pointer
icount dw 0 ; number of chars in buffer
obuffer db OBUFFSIZE dup (0) ; output buffer
oputptr dw 0 ; output put pointer
ogetptr dw 0 ; output get pointer
ocount dw 0 ; number of chars in buffer
count1 dw 0 ; counter no. 1 for timeouts
count2 dw 0 ; counter no. 2 for timeouts
no_carrier db 0 ; carrier lost
no_cts db 0 ; CTS lost
no_rts db 0 ; RTS taken down
no_xon db 0 ; Have received a XOFF
no_xoff db 0 ; Have sent an XOFF
prime db 1 ; prime required
isr_table label word ; Table of isr service routines
dw offset comm_modem ; modem status routine
dw offset comm_tx ; TX buffer empty routine
dw offset comm_rx ; RX data available routine
dw offset comm_line ; line status routine
;==========================
; Code Section
;==========================
_dmcomm_init proc far
;
;==========================
; Comm Port Initialization
;==========================
; Procedure: 1. Save the passed parameters
; 2. Init flags & pointers
; 3. Save old hardware settings
; 4. Save old interrupt vectors
; 5. If int driven then set new vectors
; 6. Setup new hardware masks
; 7. Force RTS to allow data flow
; 8. Exit all done
; Entry: BP+6 : Port Value for i/o port (hex address) (8250 assumed)
; BP+8 : Port Value for i/o port (hex address) (8250 assumed)
; BP+10: IRQ Number to use for port (0-7) (8259A assumed)
; BP+12: Access control flag (0=BIOS/Fossil, 1=Direct access,
; 2=Interrupt driven)
; BP+14: Handshake control flag (0=None, 1=XON/XOFF,
; 2=RTS/CTS, 3=BOTH)
; BP+16: Interrupt passthrough (0=No, 1=Yes)
; Return: AX = -1 if error
; AX = 0 if init processed ok
;
;
; Access the stack frame
;
push bp ; save c stack frame
mov bp,sp
push es ; save environment
push ds
push di
push si
mov ax,cs ; point to data
mov ds,ax
;
; Save configuration
;
mov ax,[bp+6] ; store the comm port id
mov commid,ax
mov ax,[bp+8] ; store the comm port base address
mov cport,ax
;
mov ax,[bp+10] ; compute interrupt vector address
cmp ax,7 ; test if valid
jbe comm_init_00
comm_init_err:
mov ax,-1 ; flag error
jmp comm_init_done ; exit
;
comm_init_00:
add ax,IRQ0V
mov cirqv,al
mov ax,1 ; compute interrupt mask
mov cx,[bp+10]
or cl,cl
jz comm_init_10
shl ax,cl
comm_init_10:
mov cirqm,al
;
mov ax,[bp+12] ; store access control flag
cmp ax,2
ja comm_init_err ; flag it if error
mov usint,ax
;
mov ax,[bp+14] ; store handshake control flag
cmp ax,3
ja comm_init_err ; flag it if error
mov handsh,ax
;
mov ax,[bp+16] ; store interrupt passthrough flag
cmp ax,1
ja comm_init_err ; flag it if error
mov passth,ax
;
; Init buffer flags and pointers
;
mov iputptr,0 ; input put pointer
mov igetptr,0 ; input get pointer
mov icount,0 ; buffer is empty
mov oputptr,0 ; output put pointer
mov ogetptr,0 ; output get pointer
mov ocount,0 ; buffer is empty
;
mov count1,0 ; clear counters
mov count2,0 ; clear counters
;
mov no_carrier,0 ; carrier lost
mov no_cts,0 ; CTS lost
mov no_rts,0 ; RTS taken down
mov no_xon,0 ; Have received a XOFF
mov no_xoff,0 ; Have sent an XOFF
mov prime,1 ; prime required
;
; Save 8255 int flags, comm port flags, and int vector
;
cli ; Keep the world quiet
mov dx,iport ; Save the 8259 INT flags
add dx,IMSK
in al,dx
mov isave,al
;
mov bx,cport ; Base port
mov dx,bx ; Save the 8250 INT flags
add dx,EINT
in al,dx
mov sisave,al
mov dx,bx ; Save the 8250 Modem flags
add dx,MCRR
in al,dx
mov smsave,al
;
mov ah,DOS_GET_VECTOR ; Save original interrupt vectors
mov al,cirqv
int DOS
mov word ptr oldint,bx
mov word ptr oldint+2,es
;
; Get initial values for line and modem status
;
cli ; Keep the world quiet
IF STAW ;*********************************************************************
mov dx,cport ; get line status port
add dx,STAT
in al,dx ; get the data
ELSE
mov al,STTX+STTH ; not monitoring, set it always ok
ENDIF ;*********************************************************************
mov clstat,al ; save it
mov dx,cport ; get line status port
add dx,MODM
in al,dx ; get the data
mov cmstat,al ; save it
;
; If int driven, Redirect ints to ISR
;
cmp usint,2 ; Test if interrupt driven
jne comm_init_20 ; Skip if not
;
push ds
mov ax,SEG _dmcomm_isr
mov ds,ax
mov dx,OFFSET _dmcomm_isr
mov ah,DOS_SET_VECTOR ; Save original interrupt vectors
mov al,cirqv
int DOS
pop ds
;
; If int driven, Adjust masks in 8250 and 8259A
;
cli ; Keep the world quiet
mov dx,iport ; Set the 8259 INT flag for appropriate
add dx,IMSK
in al,dx
mov ah,cirqm
xor ah,0FFH
and al,ah
out dx,al
;
mov dx,cport ; Set the 8250 INT flags
add dx,EINT
mov al,EIRX+EITX+EILS+EIMS
out dx,al
jmp comm_init_30 ; Now finish up
;
; Else Clear masks in 8250
;
comm_init_20:
;
mov dx,cport ; Clear the 8250 INT flags
add dx,EINT
mov al,0
out dx,al
;
; Set DTR & RTS to allow incomming data
;
mov dx,cport ; Set DTR & RTS to allow data
add dx,MCRR
mov al,MCRT+MCDT
out dx,al
jmp comm_init_done
;
; Set DTR & RTS & OUT2 to allow incomming data & interrupts
;
comm_init_30:
mov dx,cport ; Set DTR & RTS to allow data
add dx,MCRR
mov al,MCRT+MCDT+MCO2
out dx,al
;
; Now guarantee all interrupts are cleared
;
comm_init_40:
nop ; Allow a little time
nop
mov dx,cport ; Clear modem status
add dx,MODM
nop ; Allow a little time
nop
in al,dx
mov dx,cport ; Clear line status
add dx,STAT
nop ; Allow a little time
nop
in al,dx
mov dx,cport ; Clear RX available
add dx,DATA
nop ; Allow a little time
nop
in al,dx
mov dx,cport ; Clear TX empty
add dx,IINT
nop ; Allow a little time
nop
in al,dx
and al,IIPD ; Loop if still pending
jz comm_init_40
;
; Init the Fossil if present
;
cmp usint,0 ; dispatch
ja comm_init_done
;
; Call Fossil
;
mov ah,BCINIT ; init the driver
mov dx,commid ; get port id
mov bx,0 ; no ^C trapping
int BIOS ; do it
;
; Exit all done
;
comm_init_done:
sti ; Bring the world back to life
pop si ; restore registers
pop di
pop ds
pop es
pop bp ; clear out stack frame
ret
;
_dmcomm_init endp
_dmcomm_release proc far
;
;==========================
; Comm Port Release
;==========================
; Procedure: 1. Restore old hardware settings
; 2. Restore INT vector
; 3. Exit all done
; Entry: None
; Return: None
;
push es ; Save
push ds
push di
push si
mov ax,cs ; Access local storage
mov ds,ax
cli ; Keep the world quiet
;
; Restore 8255 int flags, comm port flags, and int vector
;
mov dx,iport ; Restore the 8259 INT flags
add dx,IMSK
mov al,isave
out dx,al
;
mov bx,cport ; Base port
mov dx,bx ; Save the 8250 INT flags
add dx,EINT
mov al,sisave
out dx,al
mov dx,bx ; Save the 8250 Modem flags
add dx,MCRR
mov al,smsave
out dx,al
;
mov dx,word ptr [oldint]
mov bx,word ptr [oldint+2]
mov ah,DOS_SET_VECTOR ; Save original interrupt vectors
mov al,cirqv
mov ds,bx
int DOS
;
; Exit all done
;
sti ; Alive once again
pop si ; restore registers
pop di
pop ds
pop es
ret
;
_dmcomm_release endp
_dmcomm_status proc far
;
;==========================
; Comm Port Status
;==========================
; Procedure: 1. If interrupts enabled goto 6
; 2. Read modem status
; 3. Return -1 if no carrier
; 4. Read line status
; 5. Return char available status
; 6. Return -1 if no carrier
; 7. Test input pointers
; 8. Return char available status
; Entry: None
; Return: AX = -1 if loss of carrier
; AX = 0 if no data available
; AX = 1 if character available
;
push es ; save callers regs
push ds
push di
push si
mov ax,cs ; point to storage
mov ds,ax
;
; Dispatch based on access
;
cmp usint,1 ; dispatch
je comm_status_10
ja comm_status_50
;
; Call BIOS/Fossil
;
comm_status_00:
mov ah,BCSTAT ; read the registers
mov dx,commid ; get port id
int BIOS ; get the status
IF DCDW ;*********************************************************************
jmp comm_status_02 ; DCDW: skip DCD test
ENDIF ;*********************************************************************
and al,MODC ; test for carrier
jnz comm_status_02
mov no_carrier,1 ; flag no carrier
mov ax,-1
jmp comm_status_90 ; and exit
;
comm_status_02:
mov al,0 ; assume no character
and ah,STRX ; test if data available
jz comm_status_04 ; exit all done if no char
mov ax,1 ; else flag char available
comm_status_04:
jmp comm_status_90 ; exit all done
;
; Read ports directly
;
comm_status_10:
IF DCDW ;*********************************************************************
jmp comm_status_20 ; DCDW: skip DCD test
ENDIF ;*********************************************************************
mov dx,cport ; get base port
add dx,MODM ; get modem status
in al,dx
and al,MODC ; test for carrier
jnz comm_status_20
mov no_carrier,1 ; flag no carrier
mov ax,-1
jmp comm_status_90 ; and exit
;
comm_status_20:
mov dx,cport ; get base port
add dx,STAT ; get line status
in al,dx
and al,STRX
jz comm_regs_90 ; exit all done if no char
mov ax,1 ; else flag char available
jmp comm_regs_90 ; exit all done
;
; Read last stored values
;
comm_status_50:
cli ; freeze the system
cmp no_carrier,1 ; test for carrier
jne comm_status_60 ; continue if carrier exists
mov ax,-1 ; else flag no carrier
sti ; alive again
jmp comm_status_90 ; and exit
;
comm_status_60:
cmp icount,0 ; test if empty
sti ; alive again
mov ax,0 ; assume no data avail
je comm_status_90 ; exit if none avail
inc ax ; else flag character available
;
; Restore regs & exit
;
comm_status_90:
pop si ; restore registers
pop di
pop ds
pop es
ret ; return to caller
;
_dmcomm_status endp
_dmcomm_regs proc far
;
;==========================
; Comm Port Status Regs
;==========================
; Procedure: 1. If using ints, get stored values
; 2. Else read port values
; 3. exit
; Entry: None
; Return: AH = Line Status
; AL = Modem status
;
push es ; save callers regs
push ds
push di
push si
mov ax,cs ; point to storage
mov ds,ax
;
; Dispatch based on access type
;
cmp usint,1 ; dispatch
je comm_regs_10
ja comm_regs_50
;
; Read regs via the BIOS/Fossil
;
comm_regs_00:
mov ah,BCSTAT ; read the registers
mov dx,commid ; get port id
int BIOS ; get the status
jmp comm_regs_90 ; exit all done
;
; Read ports directly
;
comm_regs_10:
mov dx,cport ; get base port
add dx,STAT ; get line status
in al,dx
mov ah,al ; it is returned in AH
mov dx,cport ; get base port
add dx,MODM ; get control status
in al,dx ; it is returned in AL
jmp comm_regs_90 ; exit all done
;
; Read last stored values
;
comm_regs_50:
cli ; freeze the system
mov ah,clstat ; get last line status
mov al,cmstat ; get last modem status
sti ; alive again
;
; Restore regs & exit
;
comm_regs_90:
pop si ; restore registers
pop di
pop ds
pop es
ret ; return to caller
;
_dmcomm_regs endp
_dmcomm_input proc far
;
;==========================
; Comm Port Input
;==========================
; Procedure: 1. If interrupt driven goto 6
; 2. Test port status
; 3. Return -1 if no carrier
; 4. If no character goto 2
; 5. Read & return character
; 6. If no carrier then return -1
; 7. If pointers are equal goto 6
; 8. Get character
; 9. Adjust pointers
; 10. If RTS down bring it back
; 11. Return character
; Entry: None
; Return: AX = -1 if no carrier
; AX = character otherwise
;
push es ; save callers registers
push ds
push di
push si
mov ax,cs ; point to storage
mov ds,ax
;
; Dispatch based on access type
;
cmp usint,1 ; dispatch
je comm_input_10
ja comm_input_50
;
; Access the BIOS/Fossil driver
;
comm_input_00:
call _dmcomm_status ; test if character available
cmp ax,-1 ; no carrier?
je comm_input_02 ; exit if so
cmp al,1 ; char available
jne comm_input_00 ; loop if not
;
mov ah,BCIN ; input a character
mov dx,commid ; get port id
int BIOS ; get the status
comm_input_02:
jmp comm_input_90 ; exit with the character
;
; Read port info directly
;
comm_input_10:
call _dmcomm_status ; test if character available
cmp ax,-1 ; no carrier?
je comm_input_90 ; exit if so
cmp al,1 ; char available
jne comm_input_10 ; loop if not
;
mov dx,cport ; get base port
add dx,DATA ; index to data
in al,dx ; read the character
jmp comm_input_90 ; exit with the character
;
; Else test the pointers & flags
;
comm_input_50:
cli ; freeze the world
cmp no_carrier,1 ; carrier lost ?
jne comm_input_60 ; continue if not
sti ; alive again
mov ax,-1 ; flag loss of carrier
jmp comm_input_90 ; and exit
;
comm_input_60:
mov bx,igetptr ; get pointer
cmp icount,0 ; test if empty
jne comm_input_70 ; continue if not (char available)
sti ; alive again
nop ; some delay
nop
nop
jmp comm_input_50 ; try again
;
comm_input_70:
lea si,ibuffer ; point to buffer
mov al,[si][bx] ; get the data
mov ah,0 ; clear upper value
;
inc bx ; adjust pointer
and bx,IBUFFMASK
mov igetptr,bx ; save new value
dec icount
sti
;
cmp no_rts,1 ; RTS down?
jne comm_input_80 ; exit if done
cli
mov bx,ax ; save input
mov dx,cport ; get base port
add dx,MCRR
mov al,MCRT+MCDT+MCO2 ; bring RTS back up
out dx,al
mov no_rts,0 ; and flag as up
sti
;
comm_input_80:
cmp no_xoff,1 ; paused?
jne comm_input_82 ; skip if not
mov al,XON ; else bring up input
call comm_char
;
comm_input_82:
;
; Restore regs & exit
;
comm_input_90:
pop si ; restore registers
pop di
pop ds
pop es
ret ; return to caller
;
_dmcomm_input endp
_dmcomm_output proc far
;
;==========================
; Comm Port Output
;==========================
; Procedure: 1. If no carrier then abort
; 2. If interrupt driven then goto 11
; 3. Test for TX buffer empty
; 4. Goto 3 if not empty
; 5. Test for CTS active
; 6. Goto 5 if not active
; 7. Output character & exit
; 8. Test if prime flag set
; 9. Goto 11 if not
; 10. Output character & exit
; 11. Test if prime required
; 12. Goto 3 if so
; 13. Test if space available in out put buffer
; 14. Goto 13 if none
; 15. Store character in output buffer
; 16. Adjust pointers & exit
; Entry: [BP+6] = character to output
; Return: AX = -1 if no carrier
; AX = 0 if all ok
; AX = 1 if timeout
;
push bp ; setup stack frame
mov bp,sp
push es ; save callers registers
push ds
push di
push si
mov ax,cs ; access storage
mov ds,ax
;
; Dispatch based on access type
;
cmp usint,1 ; dispatch
jb comm_output_00
je comm_output_05
jmp comm_output_50
;
; Process via BIOS/Fossil
;
comm_output_00:
IF DCDW ;*********************************************************************
jmp comm_output_02 ; DCDW: skip DCD test
ENDIF ;*********************************************************************
mov ah,BCSTAT ; read the registers
mov dx,commid ; get port id
int BIOS ; get the status
and al,MODC ; test for carrier
jnz comm_output_02
mov ax,-1 ; flag as no carrier
jmp comm_output_90 ; and exit
comm_output_02:
mov ax,[bp+6] ; get the character
mov ah,BCOUT ; output a character
mov dx,commid ; get port id
int BIOS ; get the status
mov al,0 ; assume all went well
and ah,BCTIME ; test for timeout
jz comm_output_04
mov ax,1 ; flag the timeout
comm_output_04:
jmp comm_output_90 ; exit all done
;
; Read ports directly
;
comm_output_05:
call time_start ; full max allowed
mov dx,cport ; get base port
add dx,MODM
comm_output_10:
IF DCDW ;*********************************************************************
jmp comm_output_15 ; DCDW: skip DCD test
ENDIF ;*********************************************************************
cli
in al,dx ; get current status
sti
test al,MODC ; test if carrier still present
jnz comm_output_15 ; continue if so
mov ax,-1 ; flag as no carrier
jmp comm_output_90 ; and exit
comm_output_15:
test al,MOCT ; test if ready to receive the output
jnz comm_output_20 ; continue if so
call time_tick ; timeout?
jnz comm_output_10 ; else loop
mov ax,1 ; else flag as timeout
jmp comm_output_90 ; and exit
;
comm_output_20:
call time_start ; full max allowed
mov dx,cport ; get base port
add dx,STAT
comm_output_30:
cli
in al,dx ; get current status
sti
and al,STTX+STTH ; test if ready to output
cmp al,STTX+STTH
jz comm_output_40 ; done if so
call time_tick ; timeout?
jnz comm_output_30 ; else loop
mov ax,1 ; else flag as timeout
jmp comm_output_90 ; and exit
comm_output_40:
mov dx,cport ; get base port
add dx,DATA ; get data port
mov al,[bp+6] ; get char to output
out dx,al ; send it out
xor ax,ax ; flag as no error
mov prime,0 ; we are primed
jmp comm_output_90 ; and exit
;
comm_output_50:
cli ; no interruptions please
cmp prime,1 ; need priming?
je comm_output_70 ; output char manually if so
comm_output_52:
cmp no_carrier,1 ; loss of carrier?
jne comm_output_60
mov ax,-1 ; flag as no carrier
jmp comm_output_89
comm_output_60:
call time_start ; full timeout allowed
comm_output_62:
cli
cmp ocount,OBUFFFULL ; test if buffer is full
jb comm_output_64 ; continue if not
sti
call time_tick ; timeout?
jnz comm_output_62 ; and try again if not timeout
mov ax,1 ; flag as a timeout
jmp comm_output_89
;
comm_output_64:
mov al,[bp+6] ; get char to output
lea si,obuffer ; point to buffer
mov bx,oputptr ; get index pointer
mov [si][bx],al ; store it
inc bx ; bump to next location
and bx,OBUFFMASK ; adjust for circular buffer
mov oputptr,bx ; store for later
inc ocount ; bump output count
jmp comm_output_89 ; exit
;
comm_output_70:
cmp ocount,0 ; is buffer empty?
jnz comm_output_52 ; store in buffer if not
call time_start ; full max allowed
comm_output_72:
sti
mov al,cmstat ; get status
IF DCDW ;*********************************************************************
jmp comm_output_75 ; DCDW: skip DCD test
ENDIF ;*********************************************************************
test al,MODC ; test if carrier still present
jnz comm_output_75 ; continue if so
mov ax,-1 ; flag as no carrier
jmp comm_output_90 ; and exit
comm_output_75:
test al,MOCT ; test if ready to receive the output
jnz comm_output_80 ; continue if so
call time_tick ; timeout?
jnz comm_output_72 ; else loop
mov ax,1 ; else flag as timeout
jmp comm_output_90 ; and exit
;
comm_output_80:
mov al,clstat ; get current status
and al,STTX+STTH ; test if ready to output
cmp al,STTX+STTH
jz comm_output_85 ; done if so
call time_tick ; timeout?
jnz comm_output_80 ; else loop
mov ax,1 ; else flag as timeout
jmp comm_output_89 ; and exit
comm_output_85:
cli ; no interruptions
mov dx,cport ; get base port
add dx,DATA ; get data port
mov al,[bp+6] ; get char to output
out dx,al ; send it out
xor ax,ax ; flag as no error
mov prime,0 ; we are primed
;
comm_output_89:
sti ; alive again
;
comm_output_90:
pop si ; restore c registers
pop di
pop ds
pop es
pop bp ; restore stack frame
ret
;
_dmcomm_output endp
_dmcomm_wait proc far
;
;==========================
; Comm Port Wait
;==========================
; Procedure: 1. If not interrupt then exit
; 2. If no carrier then exit
; 3. If output buffer not empty, goto 2
; 4. Exit
; Entry: None
; Return: AX = -1 if no carrier
; AX = 0 if all ok
; AX = 1 if timeout
;
push es ; save callers registers
push ds
push di
push si
mov ax,cs ; access storage
mov ds,ax
;
; Dispatch based on access type
;
cmp usint,1 ; dispatch
je comm_wait_05
ja comm_wait_50
;
; Process via Fossil
;
comm_wait_00:
IF DCDW ;*********************************************************************
jmp comm_wait_02 ; DCDW: skip DCD test
ENDIF ;*********************************************************************
mov ah,BCSTAT ; read the registers
mov dx,commid ; get port id
int BIOS ; get the status
and al,MODC ; test for carrier
jnz comm_wait_02
mov ax,-1 ; flag as no carrier
jmp comm_wait_90 ; and exit
comm_wait_02:
mov ah,BCWAIT ; wait for comm output complete
mov dx,commid ; port id
int BIOS
jmp comm_wait_90 ; exit
;
; Read ports directly
;
comm_wait_05:
mov bx,0 ; full max allowed
mov dx,cport ; get base port
add dx,MODM
comm_wait_10:
IF DCDW ;*********************************************************************
jmp comm_wait_15 ; DCDW: skip DCD test
ENDIF ;*********************************************************************
cli
in al,dx ; get current status
sti
test al,MODC ; test if carrier still present
jnz comm_wait_15 ; continue if so
mov ax,-1 ; flag as no carrier
jmp comm_wait_90 ; and exit
comm_wait_15:
mov ax,0 ; else flag as ok
jmp comm_wait_90 ; and exit
;
;
comm_wait_50:
call time_start ; full timeout allowed
cmp no_carrier,1 ; loss of carrier?
jne comm_wait_60
mov ax,-1 ; flag as no carrier
jmp comm_wait_90
comm_wait_60:
cmp ocount,0 ; test if buffer is empty
je comm_wait_70 ; exit all done if so
call time_tick ; timeout?
jnz comm_wait_60 ; and try again if not timeout
mov ax,1 ; flag as a timeout
jmp comm_wait_90
;
comm_wait_70:
mov ax,0 ; no errors
;
;
comm_wait_90:
pop si ; restore c registers
pop di
pop ds
pop es
ret
;
_dmcomm_wait endp
_dmcomm_iflush proc far
;
;==========================
; Comm Port Flush Input
;==========================
; Procedure: 1. Reset all input parms
; 2. If RTS down, bring it back up
; 3. If XOFF send, send XON
; 4. Exit
; Entry: None
; Return: None
;
push es ; save C registers
push ds
push di
push si
mov ax,cs
mov ds,ax
;
; Dispatch based on access type
;
cmp usint,1 ; dispatch
je comm_if_90
ja comm_if_10 ; ignore if not
;
; Process via Fossil
;
comm_if_00:
call _dmcomm_status ; test if character available
cmp ax,-1 ; no carrier?
je comm_if_90 ; exit if so
cmp al,1 ; char available
jne comm_if_90 ; exit if not
;
mov ah,BCIN ; input a character
mov dx,commid ; get port id
int BIOS ; get the character
jmp comm_if_00 ; test if still more to purge
;
; Int driven code
;
comm_if_10:
cli ; lock up the world
mov iputptr,0 ; input put pointer
mov igetptr,0 ; input get pointer
mov icount,0 ; buffer is empty
;
cmp no_rts,1 ; RTS taken down?
jne comm_if_20 ; skip if not
mov dx,cport ; Set DTR & RTS to allow data
add dx,MCRR
mov al,MCRT+MCDT
out dx,al
jmp comm_if_80
;
comm_if_20:
cmp no_xoff,1 ; Have sent an XOFF?
jne comm_if_80 ; skip if not
mov al,XON ; Else bring it back up
call comm_char
;
comm_if_80:
sti ; alive again
;
; Exit all done
;
comm_if_90:
pop si ; restore c registers
pop di
pop ds
pop es
ret
;
_dmcomm_iflush endp
_dmcomm_oflush proc far
;
;==========================
; Comm Port Output Flush
;==========================
; Procedure: 1. Exit if not INT driven
; 2. Reset all output pointers
; 3. Set the prime flag
; Entry: None
; Return: None
;
push es ; save C registers
push ds
push di
push si
mov ax,cs
mov ds,ax
;
; Dispatch based on access type
;
cmp usint,1 ; dispatch
je comm_of_90
ja comm_of_10
;
; Process via Fossil
;
comm_of_00:
mov ah,BCFOUT ; flush output
mov dx,commid ; port id
int BIOS
jmp comm_of_90 ; exit
;
; Int driven code
;
comm_of_10:
;
cli ; lock up the world
mov oputptr,0 ; output put pointer
mov ogetptr,0 ; output get pointer
mov ocount,0 ; buffer is empty
mov prime,1 ; needs priming
sti ; alive again
;
comm_of_90:
pop si ; restore c registers
pop di
pop ds
pop es
ret
;
_dmcomm_oflush endp
_dmcomm_isr proc far
;
;==========================
; Comm Port ISR
;==========================
; Procedure: 1. Test & dispatch interrupt type.
; 2. Modem status change:
; a. If loss of DCD, set flag & goto 1.
; b. If loss of CTS, set flag & goto 1.
; c. If CTS not previously lost goto 1.
; d. Set CTS not lost
; e. If priming flag false got 1.
; f. Goto 5.
; 3. Line status change:
; a. Ignore event.
; 4. Input available:
; a. Get input char.
; b. Store in buffer.
; c. Adjust pointer.
; d. If buffer not full, goto 1.
; e. If hardware handshake, take down RTS.
; f. Goto 6.
; g. If software handshake, send XOFF.
; h. Goto 6.
; 5. Output ready:
; a. If DCD lost then goto 1.
; b. If CTS lost then goto 5d.
; c. If output chars then goto 5f.
; d. Set output priming flag.
; e. Goto 1.
; f. Get and output character.
; g. Adjust output pointer.
; h. Goto 1.
; 6. Pass on to regular ISR.
; Entry: None
; Return: None, all registers preserved
;
push ds ; save environment
push si
push dx
push bx
push ax
mov ax,cs ; access to local data
mov ds,ax
sti
;
; 1. Test & dispatch interrupt type.
;
comm_isr_10:
mov dx,cport ; get interrupt event
add dx,IINT
in al,dx
test al,IIPD
jnz comm_isr_90
jmp comm_isr_30
comm_isr_20:
mov dx,cport ; get interrupt event
add dx,IINT
in al,dx
test al,IIPD
jnz comm_isr_90
comm_isr_30:
and ax,IIMK
lea si,isr_table ; dispatch table
add si,ax ; index to event
call [si] ; dispatch based on event
jmp comm_isr_20 ; repeat till done
;
; 6. Pass on to regular ISR.
;
comm_isr_90:
cmp passth,0 ; no passthrough?
je comm_isr_95
pop ax ; restore environment
pop bx
pop dx
pop si
pop ds
jmp dword ptr cs:[oldint]
;
; 6. Default ISR exit if no other devices
;
comm_isr_95:
mov dx,iport ; get port to do EOI
add dx,IEOI
mov al,EOID ; value to output
out dx,al
pop ax ; restore environment
pop bx
pop dx
pop si
pop ds
iret ; done processing interrupt
;
;
_dmcomm_isr endp
comm_modem proc near
;
; 2. Modem status change:
;
mov dx,cport ; get modem status
add dx,MODM
in al,dx
mov cmstat,al ; save it
;
; 2a. If loss of DCD, set flag & goto 1.
;
test al,MODC ; test for loss of carrier
jnz comm_modem_b
IF DCDW ;*********************************************************************
jmp comm_modem_b ; DCDW: skip DCD flagging
ENDIF ;*********************************************************************
mov no_carrier,1 ; flag carrier lost
ret ; and exit
;
; 2b. If loss of CTS, set flag & goto 1.
;
comm_modem_b:
test handsh,2 ; test if hardware handshaking?
jnz comm_modem_b2 ; continue if so
ret ; else ignore it
;
comm_modem_b2:
test al,MOCT ; test for loss of CTS
jnz comm_modem_c
mov no_cts,1 ; flag CTS lost
ret ; and exit
;
; 2c. If CTS not previously lost goto 1.
;
comm_modem_c:
cmp no_cts,1 ; test if we suddenly got CTS
je comm_modem_d ; exit if no change
ret ; else we are done
;
; 2d. Set CTS not lost
;
comm_modem_d:
mov no_cts,0 ; clear flag
;
; 2e. If priming flag false got 1.
;
cmp prime,1 ; needs priming?
je comm_modem_e ; do it if so
ret ; else all done
;
; 2f. Goto 5.
;
comm_modem_e:
jmp comm_tx ; go transmit a character
;
comm_modem endp
comm_line proc near
;
; 3. Line status change:
;
mov dx,cport ; get line status port
add dx,STAT
in al,dx ; get the data
mov clstat,al ; save it
ret ; ignore the errors or events
;
comm_line endp
comm_rx proc near
;
; 4. Input available:
; 4a. Get input char.
;
mov dx,cport ; get data port
add dx,DATA
in al,dx ; get the data
test handsh,1 ; test if we have software handshaking
jz comm_rx_b ; skip if not
cmp al,XOFF ; test for XOFF
jne comm_rx_a2 ; continue if not
mov no_xon,1 ; else flag as paused
;
comm_rx_a1:
ret
;
comm_rx_a2:
cmp al,XON ; test if XON
jne comm_rx_b ; continue if not
cmp no_xon,1 ; was it down?
mov no_xon,0 ; clear it
jne comm_rx_a1 ; exit if it was not already set
;
cmp prime,1 ; needs priming?
jne comm_rx_a1 ; exit if not
jmp comm_tx ; else go transmit a character
;
; 4b. Store in buffer.
;
comm_rx_b:
lea si,ibuffer ; point to buffer
mov bx,iputptr ; get index pointer
mov [si][bx],al ; store it
;
; 4c. Adjust pointer.
;
inc bx ; bump to next location
and bx,IBUFFMASK ; adjust for circular buffer
mov iputptr,bx ; store for later
inc icount ; bump counter
;
; 4d. If buffer not full, goto 1.
;
cmp icount,IBUFFFULL ; test if buffer is now full
jae comm_rx_e ; take down RTS if full
ret ; else done
;
; 4e. Take down RTS.
; 4f. Goto 1.
;
comm_rx_e:
test handsh,2 ; hardware handshake?
jz comm_rx_g ; skip if not
mov no_rts,1 ; flag rts as down
mov dx,cport ; get modem control port
add dx,MCRR
mov al,MCDT+MCO2 ; set DTR true, RTS false
out dx,al
ret ; and exit
;
; 4g. Send and XOFF.
; 4h. Goto 1.
;
comm_rx_g:
test handsh,1 ; software handshake?
jz comm_rx_h ; skip if not
cmp no_xoff,1 ; already down?
je comm_rx_h ; skip if so
mov no_xoff,1 ; flag as paused
mov dx,cport ; get modem data port
add dx,DATA
mov al,XOFF ; send the XOFF
call comm_char
;
comm_rx_h:
ret ; and exit
;
comm_rx endp
comm_tx proc near
;
; 5. Output ready:
; 5a. If DCD lost then goto 1.
;
cmp no_carrier,1 ; test for loss of carrier
jne comm_tx_b ; continue if not
ret ; else exit
;
; 5b. If CTS lost then goto 5d.
;
comm_tx_b:
cmp no_cts,1 ; test for loss of CTS
je comm_tx_d ; flag prime needed if so
;
; 5c. If output chars then goto 5f.
;
lea si,obuffer ; point to output buffer
mov bx,ogetptr ; get output pointer
cmp ocount,0 ; test if empty
jne comm_tx_f ; output char if not
;
; 5d. Set output priming flag.
; 5e. Goto 1.
;
comm_tx_d:
mov prime,1 ; set prime needed
ret ; and exit
;
; 5f. Get and output character.
;
comm_tx_f:
mov dx,cport ; get data port
add dx,DATA
mov al,[si][bx] ; get character to output
out dx,al ; output it
;
; 5g. Adjust output pointer.
; 5h. Goto 1.
;
inc bx ; bump get pointer
and bx,OBUFFMASK ; adjust for circular buffer
mov ogetptr,bx ; store it back for later
dec ocount ; drop output count
ret ; exit all done
;
comm_tx endp
comm_char proc near
;
;==========================
; Send a Char to Comm
;==========================
; Procedure: 1. Wait for TX empty
; 2. Send the char
; 3. Exit
; Entry: AL contains char
; Return: None
;
push dx ; save
mov ah,al ; save the char
;
mov dx,cport ; get base port
add dx,STAT
comm_char_10:
in al,dx ; get current status
and al,STTX+STTH ; test if ready to output
cmp al,STTX+STTH
jnz comm_char_10 ; loop if not
;
mov dx,cport ; get base port
add dx,DATA
mov al,ah ; restore char
out dx,al ; and send it
;
pop dx ; restore
ret ; else exit
comm_char endp
time_start proc near
;
;==========================
; Start Timeout Timer
;==========================
; Procedure: 1. Set timer values
; 2. Exit
; Entry: None
; Return: None
;
mov cs:count1,1000H ; Init timer values
mov cs:count2,1000H
ret
;
time_start endp
time_tick proc near
;
;==========================
; Tick the Timeout Timer
;==========================
; Procedure: 1. Decrement timer
; 2. Flag if timeout
; 3. Exit
; Entry: None
; Return: zf set if timeout
;
dec cs:count2 ; One less here
jnz time_tick_90 ; Exit if not expired
;
mov cs:count2,1000H ; Reset this count
dec cs:count1 ; One less in upper timer
; Action sets the flag
;
time_tick_90:
ret ; Exit with ZF set if timeout
;
time_tick endp
DMIOSEG ends
END